﻿using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace DL.UI
{
    public class PathInfo
    {
        public string PageName;

        public PathInfo(string pageName)
        {
            PageName = pageName;
        }
    }


    public class PagePathPoint
    {
        public static string StartPageName = "MainPage"; //起始界面，不会有返回
        public static int stackCapacity = 5;

        public string basePageName; //每个节点，仅有1个BasePage

        public Stack<PathInfo>
            returnablePageNameRecord = new Stack<PathInfo>(stackCapacity); //每个节点，可能有多个PopPage，且仅记录可返回的弹窗，如缺陷提示这种弹窗不会记录

        public Stack<PathInfo> otherPageNameRecord = new Stack<PathInfo>(stackCapacity); //其他不可返回的弹窗

        // 只有在 PageMgr AddLuaPopPage 和 AddLuaBasePage 里面
        // isLua = true 其余情况没有了
        public void RecordPage(string pageName, PageType pageType)
        {
            if (string.IsNullOrEmpty(pageName))
            {
                return;
            }

            switch (pageType)
            {
                case PageType.PopPage:
                    AddPageToRecord(new PathInfo(pageName), returnablePageNameRecord);
                    break;
                case PageType.TipPage:
                    AddPageToRecord(new PathInfo(pageName), otherPageNameRecord);
                    break;
            }
        }

        public void DeRecordPage(string pageName, PageType pageType)
        {
            if (string.IsNullOrEmpty(pageName))
            {
                return;
            }

            switch (pageType)
            {
                case PageType.PopPage:
                    RemovePageFromRecord(new PathInfo(pageName), returnablePageNameRecord);
                    break;
                case PageType.TipPage:
                    RemovePageFromRecord(new PathInfo(pageName), otherPageNameRecord);
                    break;
            }
        }

        private void AddPageToRecord(PathInfo pageName, Stack<PathInfo> container)
        {
            if (container == null)
            {
                container = new Stack<PathInfo>(); //同一时间不会显示超过5个弹窗
            }

            lock (container)
            {
                var cnt = Mathf.Min(container.Count + 1, stackCapacity);
                var tempArray = new PathInfo[cnt];
                var isFull = container.Count >= stackCapacity;
                var index = 0;
                while (container.Count > 0)
                {
                    var temp = container.Pop();
                    if (temp.PageName == pageName.PageName)
                    {
                        continue;
                    }

                    if (isFull && container.Count == 0)
                    {
                        break;
                    }

                    tempArray[index++] = temp;
                }

                tempArray[index] = pageName;
                for (var i = tempArray.Length - 1; i >= 0; i--)
                {
                    if (tempArray[i] == null)
                    {
                        continue;
                    }

                    container.Push(tempArray[i]); //最上层的应该在最下面
                }
            }
        }

        private void RemovePageFromRecord(PathInfo pageName, Stack<PathInfo> container)
        {
            if (container == null || container.Count <= 0)
            {
                return;
            }

            lock (container)
            {
                var tempArray = new PathInfo[container.Count];
                var index = 0;
                while (container.Count > 0)
                {
                    var temp = container.Pop();
                    if (temp.PageName == pageName.PageName)
                    {
                        continue;
                    }

                    tempArray[index++] = temp;
                }

                for (var i = tempArray.Length - 1; i >= 0; i--)
                {
                    if (tempArray[i] == null)
                    {
                        continue;
                    }

                    container.Push(tempArray[i]);
                }
            }
        }

        public void ClearRecord()
        {
            if (returnablePageNameRecord != null)
            {
                returnablePageNameRecord.Clear();
            }

            if (otherPageNameRecord != null)
            {
                otherPageNameRecord.Clear();
            }
        }

        public void RemoveReturnablePageRecord(string pageName)
        {
            RemovePageFromRecord(new PathInfo(pageName), returnablePageNameRecord);
        }

        public override string ToString()
        {
            return string.Format("BasePage: {0}, PopPages: 个数{1}, 内容{2}, OtherPages: 个数{3}, 内容{4}", basePageName,
                returnablePageNameRecord.Count,MiniJson.Json.Serialize(returnablePageNameRecord.ToArray()),
                otherPageNameRecord.Count, MiniJson.Json.Serialize(otherPageNameRecord.ToArray()));
        }
    }


    public class PageCaches : Singleton<PageCaches> 
    {
        private readonly Dictionary<string, AbstractPage> _caches = new Dictionary<string, AbstractPage>();
        private bool _init;
        public AbstractPage GetPage(string pageName)
        {
            if (!_caches.ContainsKey(pageName))
            {
                var go = GameObject.Find(pageName);
                if (go != null)
                {
                    var page = go.GetComponent<AbstractPage>();
                    if (page != null)
                    {
                        _caches.Add(pageName, page);
                    }
                }
            }
            else
            {
                if (_caches[pageName] == null)
                {
                    Debug.LogError(pageName + " In Cache But Destroyed");
                }
            }

            return _caches.ContainsKey(pageName) ? _caches[pageName] : null;
        }
#if UNITY_EDITOR
        public string Keys
        {
            get { return MiniJson.Json.Serialize(_caches.Keys.ToArray()); }
        }
#endif

        public void Add(string pagaName, AbstractPage page)
        {
            if (!_caches.ContainsKey(pagaName))
                _caches.Add(pagaName, page);
        }


        public bool Remove(string pageName)
        {
            return _caches.Remove(pageName);
        }

        public void DestroyPage(AbstractPage page)
        {
            if (page != null)
            {
                GameObject.Destroy(page.gameObject);
                Remove(page.PageName);
            }
        }

        protected override void Construct()
        {
            gameObject.name = "PageCache";
            _init = true;
        }


        protected override void Release()
        {
            _init = false;
        }

        public void HideAllPopPage(List<string> exceptPageNames = null)
        {
            var pages = _caches.Values;
            foreach (var page in pages)
            {
                if (!page)
                {
                    continue;
                }

                if (exceptPageNames != null && exceptPageNames.Contains(page.PageName))
                {
                    continue;
                }

                if (IsPopPage(page) && page.Shown && !page.Dismissing)
                {
                    page.Hide();
                }
            }
        }

        public void HideAllSurfacePage()
        {
            foreach (var page in _caches.Values)
            {
                if (!page)
                {
                    continue;
                }

                if (page.Shown && !page.Dismissing && page.PageType == PageType.SurfacePage)
                {
                    page.Hide();
                }
            }
        }

        public bool IsPopPage(AbstractPage page)
        {
            return page.PageType == PageType.PopPage || page.PageType == PageType.TipPage;
        }

        public void Unload()
        {
            foreach (var page in _caches.Values)
            {
                DestroyImmediate(page.gameObject);
            }

            _caches.Clear();
            _pathPointsStack.Clear();
            CurrentPathPoint.ClearRecord();
        }

        public bool AnyPopPageOn()
        {
            foreach (var page in _caches.Values)
            {
                if (IsPopPage(page) && page.isActiveAndEnabled)
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 移除已记录路径最后一个节点，注意并非CurrentPathPoint
        /// </summary>
        public void RemoveLastPathPoint()
        {
            if (_pathPointsStack.Count > 0)
            {
                _pathPointsStack.Pop();
            }
        }

        public PagePathPoint PeekLastPathPoint()
        {
            if (_pathPointsStack.Count > 0)
            {
                return _pathPointsStack.Peek();
            }

            return null;
        }

        public void RemovePageFromLastPathPoint(string pageName)
        {
            if (_pathPointsStack.Count > 0)
            {
                var lastPoint = _pathPointsStack.Peek();
                if (lastPoint != null)
                {
                    lastPoint.RemoveReturnablePageRecord(pageName);
                }
            }
        }

        #region 跳转节点相关

        private readonly Stack<PagePathPoint> _pathPointsStack = new Stack<PagePathPoint>();
        public PagePathPoint CurrentPathPoint = new PagePathPoint(); //当前节点不会存在路径信息中

        /// <summary>
        /// 更新路径信息，每次BasePage显示时调用
        /// </summary>
        public void ForwardPathPoint(string basePageName)
        {
            if (CurrentPathPoint.basePageName != basePageName)
            {
                if (!string.IsNullOrEmpty(CurrentPathPoint.basePageName))
                {
                    _pathPointsStack.Push(CurrentPathPoint);
                }

                CurrentPathPoint = new PagePathPoint();
                CurrentPathPoint.basePageName = basePageName;
            }
        }

        public PagePathPoint BackwardPathPoint()
        {
            if (_pathPointsStack.Count > 0)
            {
                var path = _pathPointsStack.Pop();
                if (!string.IsNullOrEmpty(path.basePageName))
                {
                    return path;
                }
            }

            return new PagePathPoint()
            { basePageName = PagePathPoint.StartPageName }; //返回的节点必须有basePage，否则清除所有路径数据后再返回会出错
        }

        public void ClearPath()
        {
            if (_pathPointsStack.Count > 0)
            {
                _pathPointsStack.Clear();
            }
        }

        public bool CachedBasePage(string basePageName)
        {
            if (string.IsNullOrEmpty(basePageName) || _pathPointsStack.Count <= 0)
                return false;

            return _pathPointsStack.Any(p => p.basePageName.Equals(basePageName));
        }

        public static bool Exist() => Inst._init;

#if UNITY_EDITOR
        
        private void DebugPagePath()
        {
            var index = 1;
            Debug.Log("打印界面路径" + _pathPointsStack.Count);
            foreach (var pathPoint in _pathPointsStack)
            {
                Debug.Log(index + "-->" + pathPoint.ToString());
                index++;
            }
        
            Debug.Log("-->当前界面：" + CurrentPathPoint.ToString());
        }
#endif

        #endregion
    }
}